package cn.unknowpupil.init.utils.html;


import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * 请求工具类
 * @author jamesluozhiwei
 */
@Slf4j
public class HttpUtils {

    /**
     * 发送get请求
     * @param url
     * @return
     */
    public static String sendGet(String url,String charset){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        String result = null;
        try {
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                //"UTF-8"
                result = EntityUtils.toString(entity, charset);
            }
            httpGet.releaseConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String contentType)
    {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try
        {
            String urlNameString = url + "?" + param;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
            String line;
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        }
        catch (IOException e)
        {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        }
        finally
        {
            try
            {
                if (in != null)
                {
                    in.close();
                }
            }
            catch (Exception ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }
    /**
     * 发送post请求
     * @param url
     * @param params 可使用JSONObject转JSON字符串
     * @return
     */
    public static String sendPost(String url,String params){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        try {
            httpPost.setEntity(new StringEntity(params, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            return EntityUtils.toString(response.getEntity(),"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送post请求
     * @param httpUrl
     * @param param JSON字符串
     * @return
     */
    public static String doPostBase64(String httpUrl, String param) {

        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            // 通过远程url连接对象打开连接
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接请求方式
            connection.setRequestMethod("POST");
            // 设置连接主机服务器超时时间：15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取主机服务器返回数据超时时间：60000毫秒
            connection.setReadTimeout(60000);

            // 默认值为：false，当向远程服务器传送数据/写数据时，需要设置为true
            connection.setDoOutput(true);
            // 默认值为：true，当前向远程服务读取数据时，设置为true，该参数可有可无
            connection.setDoInput(true);
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的

            os.write(param.getBytes());

            // 通过连接对象获取一个输入流，向远程读取
            if (connection.getResponseCode() == 200) {

                is = connection.getInputStream();

                ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                byte[] buff = new byte[100];
                int rc = 0;
                while ((rc = is.read(buff, 0, 100)) > 0) {
                    swapStream.write(buff, 0, rc);
                }
                byte[] in2b = swapStream.toByteArray();
                String tmp = new String(in2b);
                if (tmp.indexOf("errcode") == -1)
                    return Base64.getEncoder().encodeToString(in2b);
                return tmp;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }  finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 断开与远程地址url的连接
            connection.disconnect();
        }
        return result;
    }

    /**
     * http get
     *
     * @return
     * @throws Exception
     */
    public static String get(String baseUrl, Map<String, String> param) throws Exception {
        String realUrl = baseUrl;
        StringBuffer sb = new StringBuffer();
        if (!MapUtils.isEmpty(param)) {
            int index = 0;
            for (Map.Entry<String, String> entry : param.entrySet()) {
                if (index != 0) {
                    sb.append("&");
                }
                sb.append(entry.getKey());
                sb.append("=");
                sb.append(entry.getValue());
                index++;
            }
        }
        if (sb.length() > 0) {
            realUrl = realUrl + "?" + sb.toString();
        }
        try {
            HttpGet httpget = new HttpGet(realUrl);
            CloseableHttpClient httpclient = HttpClients.createDefault();
            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                // 获取响应实体
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    return EntityUtils.toString(entity);
                }
            } finally {
                httpclient.close();
                response.close();
            }
        } catch (IOException e) {
            throw new Exception(e);
        }
        return null;
    }

    /**
     * http post
     *
     * @return
     */
    public static String post(String baseUrl, Map<String, String> param) {

        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        HttpPost httppost = new HttpPost(baseUrl);

        CloseableHttpClient httpclient = null;
        CloseableHttpResponse response = null;
        try {
            UrlEncodedFormEntity uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
            httppost.setEntity(uefEntity);

            httpclient = HttpClients.createDefault();
            response = httpclient.execute(httppost);
            // 获取响应实体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                return EntityUtils.toString(entity);
            } else {
                throw new Exception("http status=" + response.getStatusLine());
            }
        } catch (Exception ex) {
            log.warn(ex.getMessage());
            return null;
        } finally {
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {

                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {

                }
            }
        }

    }

    public static String post(String baseUrl, String body) {

        HttpPost httppost = new HttpPost(baseUrl);
        httppost.setHeader("Accept", "application/json");
        httppost.setHeader("Content-Type", "application/json;charset=utf-8");
        BasicHttpEntity httpEntity = new BasicHttpEntity();
        CloseableHttpClient httpclient = null;
        CloseableHttpResponse response = null;
        try {
            httpEntity.setContent(new java.io.ByteArrayInputStream(body.getBytes("UTF-8")));
            httpEntity.setContentLength(body.getBytes("UTF-8").length);
            httppost.setEntity(httpEntity);
            // http post请求 连接 传输请求时间 3秒
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000)
                    .build();
            httppost.setConfig(requestConfig);

            httpclient = HttpClients.createDefault();
            response = httpclient.execute(httppost);
            // 获取响应实体
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                return EntityUtils.toString(entity);
            } else {
                throw new Exception("http status=" + response.getStatusLine());
            }
        } catch (Exception ex) {
            log.warn(ex.getMessage());
            return null;
        } finally {
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {

                }
            }
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {

                }
            }
        }

    }

    /**
     * http post and return object
     *
     * @param baseUrl
     * @param param
     * @param resultClass
     * @return
     */
    public static <T> T post(String baseUrl, Map<String, String> param, Class<T> resultClass) {
        String result = post(baseUrl, param);
        return new Gson().fromJson(result, resultClass);
    }

    public static <T> T post(String baseUrl, String body, Class<T> resultClass) {
        String result = post(baseUrl, body);
        return new Gson().fromJson(result, resultClass);
    }

    public static <T> List<T> post(String baseUrl, Map<String, String> param, TypeToken<List<T>> typeToken) {
        String result = post(baseUrl, param);
        return new Gson().fromJson(result, typeToken.getType());
    }


    /**
     * http get and return object
     *
     * @param baseUrl
     * @param param
     * @param typeToken
     * @return
     * @throws Exception
     */
    public static <T> List<T> get(String baseUrl, Map<String, String> param, TypeToken<List<T>> typeToken) throws Exception {
        String result = get(baseUrl, param);
        return new Gson().fromJson(result, typeToken.getType());
    }

    public static <T> T get(String baseUrl, Map<String, String> param, Class<T> resultClass) throws Exception {
        String result = get(baseUrl, param);
        return new Gson().fromJson(result, resultClass);
    }

}
